/* Copyright (c) 1997-2009
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
   http://www.polymake.de

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
--------------------------------------------------------------------------------
   $Project: polymake $$Id: hash_map 9298 2009-09-02 23:10:56Z gawrilow $
*/

#ifndef _POLYMAKE_HASH_MAP
#define _POLYMAKE_HASH_MAP

#ifndef _POLYMAKE_COMPARATORS_H
#  include <comparators.h>
#endif

#if defined(__GNUC__)
#if __GNUC__>4 || __GNUC__==4 && __GNUC_MINOR__>=2
#  include <tr1/unordered_map>
#  include <hash_iterators.h>
#  define pm_hash_map_impl std::tr1::unordered_map
#else  // gcc<=4.1
#  include <ext/hash_map>
#  define pm_hash_map_impl __gnu_cxx::hash_map
#endif

namespace pm {

template <typename Key, typename Value, typename KeyComparator=operations::cmp>
class hash_map : public pm_hash_map_impl<Key,Value,hash_func<Key>,operations::cmp2eq<KeyComparator,Key> > {
   typedef pm_hash_map_impl<Key,Value,hash_func<Key>,operations::cmp2eq<KeyComparator,Key> > _super;
public:
   hash_map() {}
   explicit hash_map(size_t start_cap) : _super(start_cap) {}

   template <typename Iterator>
   hash_map(Iterator first, Iterator last) : _super(first,last) {}

   typename _super::iterator
   insert(typename function_argument<Key>::type k)
   {
      return _super::insert(typename _super::value_type(k)).first;
   }

   template <typename Operation>
   typename _super::iterator
   insert(typename function_argument<Key>::type k, const Operation& op, typename disable_if<int, identical<Operation,Value>::value>::type=0)
   {
      std::pair<typename _super::iterator,bool> ret=_super::insert(typename _super::value_type(k));
      if (!ret.second) op(ret.first->second);
      return ret.first;
   }

   typename _super::iterator
   insert(typename function_argument<Key>::type k, typename function_argument<Value>::type v)
   {
      std::pair<typename _super::iterator,bool> ret=_super::insert(typename _super::value_type(k,v));
      if (!ret.second) ret.first->second=v;
      return ret.first;
   }

   template <typename Operation>
   typename _super::iterator
   insert(typename function_argument<Key>::type k, typename function_argument<Value>::type v, const Operation& op)
   {
      std::pair<typename _super::iterator,bool> ret=_super::insert(typename _super::value_type(k,v));
      if (!ret.second) op(ret.first->second,v);
      return ret.first;
   }

   std::pair<typename _super::iterator,bool>
   insert(const typename _super::value_type& p) { return _super::insert(p); }

   template <typename Iterator>
   void insert(Iterator first, Iterator last, typename disable_if<int, identical<Iterator,Key>::value && identical<Iterator,Value>::value>::type=0)
   {
      _super::insert(first,last);
   }
};

template <typename Key, typename Value, typename KeyComparator>
struct spec_object_traits< hash_map<Key,Value,KeyComparator> >
   : spec_object_traits<is_container> {
   static const IO_separator_kind IO_separator=IO_sep_inherit;
};

// FIXME: soon deprecated
template <typename Key, typename Value, typename HashFcn=hash_func<Key>, typename EqualKey=std::equal_to<Key> >
class hash_map_as_property_map
   : public pm_hash_map_impl<Key, Value, HashFcn, EqualKey> {
   typedef pm_hash_map_impl<Key, Value, HashFcn, EqualKey> _super;
public:
   hash_map_as_property_map() {}

   explicit hash_map_as_property_map(size_t start_cap)
      : _super(start_cap) {}

   Value& operator() (const Key& k)
   {
      return (_super::insert(typename _super::value_type(k, def_val))).first->second;
   }

   const Value& operator() (const Key& k) const
   {
      typename _super::const_iterator ii=this->find(k);
      return ii==this->end() ? def_val : ii->second;
   }

   std::pair<typename _super::iterator, bool>
   insert(const Key& k, typename function_argument<Value>::type v)
   {
      return _super::insert(typename _super::value_type(k, v));
   }

   void set_default_value(typename function_argument<Value>::type default_value)
   {
      def_val=default_value;
   }
protected:
   Value def_val;
};

} // end namespace pm

namespace polymake {
   using pm::hash_map;
}

#undef pm_hash_map_impl

#endif // GNUC
#endif // _POLYMAKE_HASH_MAP

// Local Variables:
// mode:C++
// End:
